package com.wzdigit.wms.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wzdigit.framework.utils.DateUtils;
import com.wzdigit.wms.basic.domain.basic.Vehicle;
import com.wzdigit.wms.common.entity.ExcelExportConfig;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author : gong.hl
 * @time ：2019-01-18
 * @desc ：Excel import | export
 */
public class HttpExcel {

	
    /**
     * 生成 Workbook ，用于导出数据 [ 2003 版本 xls 文件]
     *
     * @param list       ：需要导出的数据
     * @param title      ：标题数组
     * @param properties ：属性数组
     * @param size       ：每列宽度 数组
     * @param <T>
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static <T> HSSFWorkbook listToExcel(List<T> list, String[] title, String[] properties, Integer[] size)
            throws NoSuchFieldException, IllegalAccessException {
        // 判断是否为空
        if (list == null) {
            return null;
        }

        // 二、新建excel表格各种对象、各种样式 //创建一个workbook = 一个excel文件
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 创建一个sheet，可指定名称
        HSSFSheet sheet = workbook.createSheet("sheet");

        // 标题风格
        HSSFCellStyle titleStyle = titleStyle(workbook);
        // 列风格
        HSSFCellStyle columnStyle = columnStyle(workbook);

        // 三、插入表头行  循环结束，表头行就出来了
        // 所有属性名构成表头行，每一个对象有多少属性 = 有多少列 = 每行有多少单元格

        // 创建表头行对象
        HSSFRow headerRow = sheet.createRow(0);
        for (int i = 0; i < title.length; i++) {
            HSSFCell cell = headerRow.createCell(i);
            cell.setCellValue(title[i]);
            // 单元格逐个引用样式
            cell.setCellStyle(titleStyle);
        }
        // 创建变量，累加值
        int count = 0;
        // 创建变量，处理新的sheet
        int sheetRow = 0;

        // 四、插入每一个数据行  
        // 一个对象 ==》 一行 ，进行插入
        for (int i = 0; i < list.size(); i++) {
            // 判断是否为 3w 的倍数 [ 数据量大时，新建sheet ]
            if ((i + 1) % 30000 == 0) {
                // 累加数量
                count++;
                // 生成新的 sheet //创建一个sheet，可指定名称
                sheet = workbook.createSheet("sheet" + count);
                // 创建表头行对象
                headerRow = sheet.createRow(0);
                for (int k = 0; k < title.length; k++) {
                    HSSFCell cell = headerRow.createCell(k);
                    cell.setCellValue(title[k]);
                    // 单元格逐个引用样式
                    cell.setCellStyle(titleStyle);
                }
                // 重置 行数
                sheetRow = 0;
            }
            // 拿出来每一个对象
            T obj = list.get(i);
            // 插入数据从第1行开始，因为第0行是表头行；
            HSSFRow row = sheet.createRow(sheetRow + 1);
            // 一个对象转成一行，保持每一列和表头行的对应
            for (int j = 0; j < title.length; j++) {
                // 调用自写静态方法得到当前对象obj的每一属性名对应的属性值
                HSSFCell cell = row.createCell(j);
                // 通过反射，获取对象中的属性值
                Field field = list.get(i).getClass().getDeclaredField(properties[j]);
                // 设置对象的访问权限，保证对private的属性的访问
                field.setAccessible(true);
                // 获取数据
                Object value = field.get(list.get(i));
                // 将属性值存入单元格
                cell.setCellValue(value != null ? value.toString() : null);
                // 单元格逐个引用样式
                cell.setCellStyle(columnStyle);
                // 设置某一列宽度
                sheet.setColumnWidth(j, size[j] * 30);
            }
            // 累加行数
            sheetRow++;
        }
        return workbook;
    }

    /**
     * 标题风格
     *
     * @param workbook ：工作簿
     * @return
     */
    public static HSSFCellStyle titleStyle(HSSFWorkbook workbook) {
        // 对整个excel生成一个样式
        HSSFCellStyle style = workbook.createCellStyle();
        // 内容水平居中 、垂直居中
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        // 背景色
        // style.setFillForegroundColor(HSSFColor.YELLOW.index);
        // style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); 
        // style.setFillBackgroundColor(HSSFColor.YELLOW.index); 
        // 设置一个字体
        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) 12);
        font.setColor(HSSFColor.BLACK.index);
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        font.setFontName("宋体");
        style.setFont(font);
        // 返回风格
        return style;
    }

    /**
     * 数据列的风格
     *
     * @param workbook ：工作簿
     * @return
     */
    public static HSSFCellStyle columnStyle(HSSFWorkbook workbook) {
        // 对整个excel生成一个样式
        HSSFCellStyle style = workbook.createCellStyle();
        // 内容水平居中 、垂直居中
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        // 背景色
        // style.setFillForegroundColor(HSSFColor.YELLOW.index);
        // style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); 
        // style.setFillBackgroundColor(HSSFColor.YELLOW.index); 

        // 设置一个字体
        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) 12);
        font.setColor(HSSFColor.BLACK.index);
        font.setBoldweight(HSSFFont.ANSI_CHARSET);
        font.setFontName("宋体");
        style.setFont(font);
        // 返回风格
        return style;
    }

    /**
     * 生成 Workbook ，用于导出数据 [ 2007 版本以上 xls文件]
     *
     * @param list       ：需要导出的数据
     * @param title      ：标题数组
     * @param properties ：属性数组
     * @param size       ：每列宽度 数组
     * @param <T>
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static <T> XSSFWorkbook newListToExcel(List<T> list, String[] title, String[] properties, Integer[] size)
            throws NoSuchFieldException, IllegalAccessException {
        // 判断是否为空
        if (list == null) {
            return null;
        }

        // 二、新建excel表格各种对象、各种样式 //创建一个workbook = 一个excel文件
        XSSFWorkbook workbook = new XSSFWorkbook();
        // 创建一个sheet，可指定名称
        XSSFSheet sheet = workbook.createSheet("sheet");

        // 标题风格
        XSSFCellStyle titleStyle = newTitleStyle(workbook);
        // 列风格
        XSSFCellStyle columnStyle = newColumnStyle(workbook);

        // 三、插入表头行  循环结束，表头行就出来了
        // 所有属性名构成表头行，每一个对象有多少属性 = 有多少列 = 每行有多少单元格

        // 创建表头行对象
        XSSFRow headerRow = sheet.createRow(0);
        for (int i = 0; i < title.length; i++) {
            XSSFCell cell = headerRow.createCell(i);
            cell.setCellValue(title[i]);
            // 单元格逐个引用样式
            cell.setCellStyle(titleStyle);
        }
        // 创建变量，累加值
        int count = 0;
        // 创建变量，处理新的sheet
        int sheetRow = 0;

        // 四、插入每一个数据行  
        // 一个对象 ==》 一行 ，进行插入
        for (int i = 0; i < list.size(); i++) {
            // 判断是否为 3w 的倍数 [ 数据量大时，新建sheet ]
            if ((i + 1) % 30000 == 0) {
                // 累加数量
                count++;
                // 生成新的 sheet //创建一个sheet，可指定名称
                sheet = workbook.createSheet("sheet" + count);
                // 创建表头行对象
                headerRow = sheet.createRow(0);
                for (int k = 0; k < title.length; k++) {
                    XSSFCell cell = headerRow.createCell(k);
                    cell.setCellValue(title[k]);
                    // 单元格逐个引用样式
                    cell.setCellStyle(titleStyle);
                }
                // 重置 行数
                sheetRow = 0;
            }
            // 拿出来每一个对象
            T obj = list.get(i);
            // 插入数据从第1行开始，因为第0行是表头行；
            XSSFRow row = sheet.createRow(sheetRow + 1);
            // 一个对象转成一行，保持每一列和表头行的对应
            for (int j = 0; j < title.length; j++) {
                // 调用自写静态方法得到当前对象obj的每一属性名对应的属性值
                XSSFCell cell = row.createCell(j);
                // 通过反射，获取对象中的属性值
                Field field = list.get(i).getClass().getDeclaredField(properties[j]);
                // 设置对象的访问权限，保证对private的属性的访问
                field.setAccessible(true);
                // 获取数据
                Object value = field.get(list.get(i));
                if (value instanceof Date) {
                    value = DateUtils.format((Date) value, DateUtils.DATETIME_FORMAT);
                }
                // 将属性值存入单元格
                cell.setCellValue(value != null ? value.toString() : null);
                // 单元格逐个引用样式
                cell.setCellStyle(columnStyle);
                // 设置某一列宽度
                sheet.setColumnWidth(j, size[j] * 30);
            }
            // 累加行数
            sheetRow++;
        }
        return workbook;
    }

    /**
     * 生成 Workbook ，用于导出数据
     *
     * @param list
     * @param configList
     * @param <T>
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static <T> XSSFWorkbook newListToExcel(List<T> list, List<ExcelExportConfig> configList)
            throws NoSuchFieldException, IllegalAccessException {

        // 判断是否为空
        if (list == null) {
            return null;
        }

        // 二、新建excel表格各种对象、各种样式 //创建一个workbook = 一个excel文件
        XSSFWorkbook workbook = new XSSFWorkbook();
        // 创建一个sheet，可指定名称
        XSSFSheet sheet = workbook.createSheet("sheet");

        // 标题风格
        XSSFCellStyle titleStyle = newTitleStyle(workbook);
        // 列风格
        XSSFCellStyle columnStyle = newColumnStyle(workbook);

        // 三、插入表头行  循环结束，表头行就出来了
        // 所有属性名构成表头行，每一个对象有多少属性 = 有多少列 = 每行有多少单元格

        // 创建表头行对象
        XSSFRow headerRow = sheet.createRow(0);
        for (int i = 0; i < configList.size(); i++) {
            XSSFCell cell = headerRow.createCell(i);
            cell.setCellValue(configList.get(i).getTitle());
            // 单元格逐个引用样式
            cell.setCellStyle(titleStyle);
        }
        // 创建变量，累加值
        int count = 0;
        // 创建变量，处理新的sheet
        int sheetRow = 0;

        // 四、插入每一个数据行  
        // 一个对象 ==》 一行 ，进行插入
        for (int i = 0; i < list.size(); i++) {
            // 判断是否为 3w 的倍数 [ 数据量大时，新建sheet ]
            if ((i + 1) % 30000 == 0) {
                // 累加数量
                count++;
                // 生成新的 sheet //创建一个sheet，可指定名称
                sheet = workbook.createSheet("sheet" + count);
                // 创建表头行对象
                headerRow = sheet.createRow(0);
                for (int k = 0; k < configList.size(); k++) {
                    XSSFCell cell = headerRow.createCell(k);
                    cell.setCellValue(configList.get(k).getTitle());
                    // 单元格逐个引用样式
                    cell.setCellStyle(titleStyle);
                }
                // 重置 行数
                sheetRow = 0;
            }
            // 拿出来每一个对象
            T obj = list.get(i);
            // 插入数据从第1行开始，因为第0行是表头行；
            XSSFRow row = sheet.createRow(sheetRow + 1);
            // 一个对象转成一行，保持每一列和表头行的对应
            for (int j = 0; j < configList.size(); j++) {
                // 调用自写静态方法得到当前对象obj的每一属性名对应的属性值
                XSSFCell cell = row.createCell(j);
                // 通过反射，获取对象中的属性值
                Field field = list.get(i).getClass().getDeclaredField(configList.get(j).getPropertyName());
                // 设置对象的访问权限，保证对private的属性的访问
                field.setAccessible(true);
                // 获取数据
                Object value = field.get(list.get(i));
                if (value instanceof Date) {
                    value = DateUtils.format((Date) value, DateUtils.DATETIME_FORMAT);
                }
                // 将属性值存入单元格
                cell.setCellValue(value != null ? value.toString() : null);
                // 单元格逐个引用样式
                cell.setCellStyle(columnStyle);
                // 设置某一列宽度
                sheet.setColumnWidth(j, configList.get(j).getColwidth() * 30);
            }
            // 累加行数
            sheetRow++;
        }
        return workbook;
    }


    /**
     * 生成 Workbook ，用于导出数据
     *
     * @param list
     * @param configList
     * @param <T>
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static XSSFWorkbook newJsonListToExcel(JSONArray list, List<ExcelExportConfig> configList)
            throws NoSuchFieldException, IllegalAccessException {

        // 判断是否为空
        if (list.isEmpty()) {
            return null;
        }

        // 二、新建excel表格各种对象、各种样式 //创建一个workbook = 一个excel文件
        XSSFWorkbook workbook = new XSSFWorkbook();
        // 创建一个sheet，可指定名称
        XSSFSheet sheet = workbook.createSheet("sheet");

        // 标题风格
        XSSFCellStyle titleStyle = newTitleStyle(workbook);
        // 列风格
        XSSFCellStyle columnStyle = newColumnStyle(workbook);

        // 三、插入表头行  循环结束，表头行就出来了
        // 所有属性名构成表头行，每一个对象有多少属性 = 有多少列 = 每行有多少单元格

        // 创建表头行对象
        XSSFRow headerRow = sheet.createRow(0);
        for (int i = 0; i < configList.size(); i++) {
            XSSFCell cell = headerRow.createCell(i);
            cell.setCellValue(configList.get(i).getTitle());
            // 单元格逐个引用样式
            cell.setCellStyle(titleStyle);
        }
        // 创建变量，累加值
        int count = 0;
        // 创建变量，处理新的sheet
        int sheetRow = 0;

        // 四、插入每一个数据行  
        // 一个对象 ==》 一行 ，进行插入
        for (int i = 0; i < list.size(); i++) {
            // 判断是否为 3w 的倍数 [ 数据量大时，新建sheet ]
            if ((i + 1) % 30000 == 0) {
                // 累加数量
                count++;
                // 生成新的 sheet //创建一个sheet，可指定名称
                sheet = workbook.createSheet("sheet" + count);
                // 创建表头行对象
                headerRow = sheet.createRow(0);
                for (int k = 0; k < configList.size(); k++) {
                    XSSFCell cell = headerRow.createCell(k);
                    cell.setCellValue(configList.get(k).getTitle());
                    // 单元格逐个引用样式
                    cell.setCellStyle(titleStyle);
                }
                // 重置 行数
                sheetRow = 0;
            }
            // 拿出来每一个对象
            JSONObject obj = list.getJSONObject(i);
            // 插入数据从第1行开始，因为第0行是表头行；
            XSSFRow row = sheet.createRow(sheetRow + 1);
            // 一个对象转成一行，保持每一列和表头行的对应
            for (int j = 0; j < configList.size(); j++) {
                // 调用自写静态方法得到当前对象obj的每一属性名对应的属性值
                XSSFCell cell = row.createCell(j);
                // 通过反射，获取对象中的属性值
                //获取Json中的值
                Object value = obj.getObject(configList.get(j).getPropertyName(), Object.class);
                if (value instanceof Date) {
                    value = DateUtils.format((Date) value, DateUtils.DATETIME_FORMAT);
                }
                // 将属性值存入单元格
                cell.setCellValue(value != null ? value.toString() : null);
                // 单元格逐个引用样式
                cell.setCellStyle(columnStyle);
                // 设置某一列宽度
                sheet.setColumnWidth(j, configList.get(j).getColwidth() * 30);
            }
            // 累加行数
            sheetRow++;
        }
        return workbook;
    }


    /**
     * 标题风格
     *
     * @param workbook ：工作簿
     * @return
     */
    public static XSSFCellStyle newTitleStyle(XSSFWorkbook workbook) {
        // 对整个excel生成一个样式
        XSSFCellStyle style = workbook.createCellStyle();
        // 内容水平居中 、垂直居中
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        // 背景色
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style.setFillBackgroundColor(HSSFColor.YELLOW.index);
        style.setFillForegroundColor(HSSFColor.YELLOW.index);
		//下边框
		style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
		//左边框
		style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
		//上边框
		style.setBorderTop(HSSFCellStyle.BORDER_THIN);
		//右边框
		style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        // 设置一个字体
        XSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) 12);
        font.setColor(HSSFColor.BLACK.index);
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        font.setFontName("宋体");
        style.setFont(font);
        // 返回风格
        return style;
    }

    /**
     * 数据列的风格
     *
     * @param workbook ：工作簿
     * @return
     */
    public static XSSFCellStyle newColumnStyle(XSSFWorkbook workbook) {
        // 对整个excel生成一个样式
        XSSFCellStyle style = workbook.createCellStyle();
        // 内容水平居中 、垂直居中
        style.setAlignment(HSSFCellStyle.ALIGN_LEFT);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        // 背景色
        // style.setFillForegroundColor(HSSFColor.YELLOW.index);
        // style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); 
        // style.setFillBackgroundColor(HSSFColor.YELLOW.index); 
		//下边框
		style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
		//左边框
		style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
		//上边框
		style.setBorderTop(HSSFCellStyle.BORDER_THIN);
		//右边框
		style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        // 设置一个字体
        XSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) 12);
        font.setColor(HSSFColor.BLACK.index);
        font.setBoldweight(HSSFFont.ANSI_CHARSET);
        font.setFontName("宋体");
        style.setFont(font);
        // 返回风格
        return style;
    }

    /**
     * 生成 Workbook ，用于导出数据 [ 海量数据导出 xls文件] 注意 ： SXSSFWorkbook 只能用于写入(导出数据)，不能用于读取
     *
     * @param list       ：需要导出的数据
     * @param title      ：标题数组
     * @param properties ：属性数组
     * @param size       ：每列宽度 数组
     * @param <T>
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static <T> SXSSFWorkbook supperListToExcel(List<T> list, String[] title, String[] properties, Integer[] size)
            throws NoSuchFieldException, IllegalAccessException {
        // 判断是否为空
        if (list == null) {
            return null;
        }

        // 二、新建excel表格各种对象、各种样式 //创建一个workbook = 一个excel文件
        // [ 当数据量到达 1000 行才会进行写入数据]
        SXSSFWorkbook workbook = new SXSSFWorkbook(1000);
        // 创建一个sheet，可指定名称
        Sheet sheet = workbook.createSheet("sheet");
        // 标题风格
        CellStyle titleStyle = supperTitleStyle(workbook);
        // 列风格
        CellStyle columnStyle = supperColumnStyle(workbook);

        // 冻结第一行
        sheet.createFreezePane(0, 1, 0, 1);

        // 三、插入表头行  循环结束，表头行就出来了
        // 所有属性名构成表头行，每一个对象有多少属性 = 有多少列 = 每行有多少单元格

        // 创建表头行对象
        Row headerRow = sheet.createRow(0);
        for (int i = 0; i < title.length; i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(title[i]);
            // 单元格逐个引用样式
            cell.setCellStyle(titleStyle);
            // 设置宽度
            sheet.setColumnWidth(i, size[i] * 30);
        }
        // 创建变量，累加值
        int count = 0;
        // 创建变量，处理新的sheet
        int sheetRow = 0;

        // 四、插入每一个数据行  
        // 一个对象 ==》 一行 ，进行插入
        for (int i = 0; i < list.size(); i++) {
            // 判断是否为 3w 的倍数 [ 数据量大时，新建sheet ]
            if ((i + 1) % 30000 == 0) {
                // 累加数量
                count++;
                // 生成新的 sheet //创建一个sheet，可指定名称
                sheet = workbook.createSheet("sheet" + count);
                // 冻结第一行
                sheet.createFreezePane(0, 1, 0, 1);
                // 创建表头行对象
                headerRow = sheet.createRow(0);
                for (int k = 0; k < title.length; k++) {
                    Cell cell = headerRow.createCell(k);
                    cell.setCellValue(title[k]);
                    // 单元格逐个引用样式
                    cell.setCellStyle(titleStyle);
                    // 设置宽度
                    sheet.setColumnWidth(k, size[k] * 30);
                }
                // 重置 行数
                sheetRow = 0;
            }
            // 拿出来每一个对象
            T obj = list.get(i);
            // 插入数据从第1行开始，因为第0行是表头行；
            Row row = sheet.createRow(sheetRow + 1);
            // 一个对象转成一行，保持每一列和表头行的对应
            for (int j = 0; j < title.length; j++) {
                // 调用自写静态方法得到当前对象obj的每一属性名对应的属性值
                Cell cell = row.createCell(j);
                // 通过反射，获取对象中的属性值
                Field field = FieldUtils.getField(list.get(i).getClass(), properties[j], true);
                // 获取数据
                Object value = null;
                try {
                    value = field.get(list.get(i));
                } catch (Exception e) {
                }
                // 判断类型 [ 如果是时间类型 ，那就进行格式化处理 ]
                if ("java.util.Date".equals(field.getType().getName())) {
                    // 判断值是否为空
                    if (value != null) {
                        // 进行转换
                        String dateValue = DateUtils.format((Date) value, "yyyy-MM-dd HH:mm:ss");
                        // 将属性值存入单元格
                        cell.setCellValue(dateValue);
                    }
                } else {
                    // 将属性值存入单元格
                    cell.setCellValue(value != null ? value.toString() : null);
                }
                // 单元格逐个引用样式
                cell.setCellStyle(columnStyle);
            }
            // 累加行数
            sheetRow++;
        }
        return workbook;
    }

    /**
     * 标题风格
     *
     * @param workbook ：工作簿
     * @return
     */
    public static CellStyle supperTitleStyle(SXSSFWorkbook workbook) {
        // 对整个excel生成一个样式
        CellStyle style = workbook.createCellStyle();
        // 内容水平居中 、垂直居中
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        // 背景色
        // style.setFillForegroundColor(HSSFColor.YELLOW.index);
        // style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); 
        // style.setFillBackgroundColor(HSSFColor.YELLOW.index); 
        // 设置一个字体
        Font font = workbook.createFont();
        font.setFontHeightInPoints((short) 12);
        font.setColor(HSSFColor.BLACK.index);
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        font.setFontName("宋体");
        style.setFont(font);
        // 返回风格
        return style;
    }

    /**
     * 数据列的风格
     *
     * @param workbook ：工作簿
     * @return
     */
    public static CellStyle supperColumnStyle(SXSSFWorkbook workbook) {
        // 对整个excel生成一个样式
        CellStyle style = workbook.createCellStyle();
        // 内容水平居中 、垂直居中
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        // 背景色
        // style.setFillForegroundColor(HSSFColor.YELLOW.index);
        // style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); 
        // style.setFillBackgroundColor(HSSFColor.YELLOW.index); 

        // 设置一个字体
        Font font = workbook.createFont();
        font.setFontHeightInPoints((short) 12);
        font.setColor(HSSFColor.BLACK.index);
        font.setBoldweight(HSSFFont.ANSI_CHARSET);
        font.setFontName("宋体");
        style.setFont(font);
        // 返回风格
        return style;
    }

    /**
     * 生成 Workbook ，用于导出数据 [ 海量数据导出 xls文件] 注意 ： SXSSFWorkbook 只能用于写入(导出数据)，不能用于读取
     *
     * @param list       ：需要导出的数据
     * @param title      ：标题集合Map [ key为标题，value为下拉框列表数据]
     * @param properties ：属性数组
     * @param size       ：每列宽度 数组
     * @param <T>
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static <T> SXSSFWorkbook supperListToExcel(List<T> list, Map<String, String[]> title, String[] properties,
                                                      Integer[] size) throws NoSuchFieldException, IllegalAccessException {
        // 判断是否为空
        if (list == null) {
            return null;
        }

        // 二、新建excel表格各种对象、各种样式 //创建一个workbook = 一个excel文件
        // [ 当数据量到达 1000 行才会进行写入数据]
        SXSSFWorkbook workbook = new SXSSFWorkbook(1000);
        // 创建一个sheet，可指定名称
        Sheet sheet = workbook.createSheet("sheet");

        // 标题风格
        CellStyle titleStyle = supperTitleStyle(workbook);
        // 列风格
        CellStyle columnStyle = supperColumnStyle(workbook);

        // 冻结第一行
        sheet.createFreezePane(0, 1, 0, 1);

        // 三、插入表头行  循环结束，表头行就出来了
        // 所有属性名构成表头行，每一个对象有多少属性 = 有多少列 = 每行有多少单元格

        // 创建表头行对象
        Row headerRow = sheet.createRow(0);
        int titleIndex = 0;
        for (String key : title.keySet()) {
            Cell cell = headerRow.createCell(titleIndex);
            cell.setCellValue(key);
            // 单元格逐个引用样式
            cell.setCellStyle(titleStyle);
            // 设置宽度
            sheet.setColumnWidth(titleIndex, size[titleIndex] * 30);
            // 判断是否有下拉列表
            if (title.get(key) == null) {
                // 将数据转为数组
                String[] box = (String[]) title.get(key);
                // 设置为下拉框
                setValidation(sheet, box, 1, 30000, titleIndex, titleIndex);
            }
            titleIndex++;
        }
        // 创建变量，累加值
        int count = 0;
        // 创建变量，处理新的sheet
        int sheetRow = 0;

        // 四、插入每一个数据行  
        // 一个对象 ==》 一行 ，进行插入
        for (int i = 0; i < list.size(); i++) {
            // 判断是否为 3w 的倍数 [ 数据量大时，新建sheet ]
            if ((i + 1) % 30000 == 0) {
                // 累加数量
                count++;
                // 生成新的 sheet //创建一个sheet，可指定名称
                sheet = workbook.createSheet("sheet" + count);
                // 冻结第一行
                sheet.createFreezePane(0, 1, 0, 1);
                // 创建表头行对象
                headerRow = sheet.createRow(0);
                int newTitleIndex = 0;
                for (String key : title.keySet()) {
                    Cell cell = headerRow.createCell(newTitleIndex);
                    cell.setCellValue(key);
                    // 单元格逐个引用样式
                    cell.setCellStyle(titleStyle);
                    // 设置宽度
                    sheet.setColumnWidth(newTitleIndex, size[newTitleIndex] * 30);
                    // 判断是否有下拉列表
                    if (title.get(key) == null) {
                        // 将数据转为数组
                        String[] box = (String[]) title.get(key);
                        // 设置为下拉框
                        setValidation(sheet, box, 1, 30000, newTitleIndex, newTitleIndex);
                    }
                    newTitleIndex++;
                }
                // 重置 行数
                sheetRow = 0;
            }
            // 拿出来每一个对象
            T obj = list.get(i);
            // 插入数据从第1行开始，因为第0行是表头行；
            Row row = sheet.createRow(sheetRow + 1);
            // 一个对象转成一行，保持每一列和表头行的对应
            for (int j = 0; j < title.size(); j++) {
                // 调用自写静态方法得到当前对象obj的每一属性名对应的属性值
                Cell cell = row.createCell(j);
                // 通过反射，获取对象中的属性值
                Field field = list.get(i).getClass().getDeclaredField(properties[j]);
                // 设置对象的访问权限，保证对private的属性的访问
                field.setAccessible(true);
                // 获取数据
                Object value = field.get(list.get(i));
                // 判断类型 [ 如果是时间类型 ，那就进行格式化处理 ]
                if ("java.util.Date".equals(field.getType().getName())) {
                    // 判断值是否为空
                    if (value == null) {
                        // 进行转换
                        String dateValue = DateUtils.format((Date) value, "yyyy-MM-dd HH:mm:ss");
                        // 将属性值存入单元格
                        cell.setCellValue(dateValue);
                    }
                } else {
                    // 将属性值存入单元格
                    cell.setCellValue(value != null ? value.toString() : null);
                }
                // 单元格逐个引用样式
                cell.setCellStyle(columnStyle);
            }
            // 累加行数
            sheetRow++;
        }
        return workbook;
    }

    /**
     * 设置某些列的值只能输入预制的数据,显示下拉框.
     *
     * @param sheet：要设置的sheet.
     * @param textlist         ：下拉框显示的内容
     * @param firstRow         ：开始行
     * @param endRow           ：结束行
     * @param firstCol         ：开始列
     * @param endCol           ：结束列
     * @return 设置好的sheet.
     */
    public static Sheet setValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol,
                                      int endCol) {
        DataValidationHelper helper = sheet.getDataValidationHelper();

        DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist);

        // 设置数据有效性加载在哪个单元格上,四个参数分别是：起始行、终止行、起始列、终止列
        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);

        DataValidation dataValidation = helper.createValidation(constraint, regions);

        // 处理Excel兼容性问题
        if (dataValidation instanceof XSSFDataValidation) {
            dataValidation.setSuppressDropDownArrow(true);
            dataValidation.setShowErrorBox(true);
        } else {
            dataValidation.setSuppressDropDownArrow(false);
        }
        // 添加到sheet中
        sheet.addValidationData(dataValidation);
        // 返回sheet
        return sheet;
    }

    /**
     * 校验是否为合并的单元格
     *
     * @param sheet  ：当前sheet
     * @param row    行下标
     * @param column 列下标
     * @return
     */
    private static boolean isRangeCell(Sheet sheet, int row, int column) {
        // 获取Excel中合并的单元格数量
        int sheetMergeCount = sheet.getNumMergedRegions();
        // 遍历
        for (int i = 0; i < sheetMergeCount; i++) {
            // 获取合并的单元格
            CellRangeAddress range = sheet.getMergedRegion(i);
            // 获取起始列
            int firstColumn = range.getFirstColumn();
            // 获取结束列
            int lastColumn = range.getLastColumn();
            // 获取起始行
            int firstRow = range.getFirstRow();
            // 获取结束行
            int lastRow = range.getLastRow();
            // 判断当前的单元格是否为合并的单元格
            if (row >= firstRow && row <= lastRow) {
                // 判断是否在范围内
                if (column >= firstColumn && column <= lastColumn) {
                    return true;
                }
            }
        }
        return false;
    }
    
    public static void main(String[] args) throws Exception {
    	Vehicle vehicle = new Vehicle();
    	Class<? extends Vehicle> classes = vehicle.getClass();
    	JSONObject json = (JSONObject)JSON.toJSON(vehicle);
    	System.out.println(json.containsKey("vehicleId"));
	}
    

    /**
     * Excel 导入
     *
     * @param input      ：输入流对象
     * @param classes    ：类类型
     * @param properties ：属性名称
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(InputStream input, Class<T> classes, String[] properties) throws IOException {
        // 判断输入流是否为空
        if (input == null) {
            return null;
        }
        // 创建变量，记录错误的行号
        long lineNumber = 0;
        Integer sheetNumber = 0;
        short cellNumber = 0;
        // 创建变量，接收标题名称
        String errorTitle = "";
        try {
            // 创建数据集合
            List<T> list = new ArrayList<>();
            // 创建 workbook
            Workbook workbook = null;
            // 判断
            if (!input.markSupported()) {
                input = new PushbackInputStream(input, 8);
            }
            // 2003版 xls
            if (POIFSFileSystem.hasPOIFSHeader(input)) {
                workbook = new HSSFWorkbook(input);
            }
            // 2007版 xlsx
            if (POIXMLDocument.hasOOXMLHeader(input)) {
                // OPCPackage.open(is)取得一个文件的读写权限
                workbook = new XSSFWorkbook(OPCPackage.open(input));
            }
            // 判断是否存在行号参数
            JSONObject jsonObj = (JSONObject)JSON.toJSON(classes.newInstance());
            boolean existRow = jsonObj.containsKey("row");
            // 获取sheet页
            Integer sheetCount = workbook.getNumberOfSheets();
            // 遍历sheet页
            for (int i = 0; i < sheetCount; i++) {

                // 获取 sheet 号
                sheetNumber = i;
                // 获取sheet
                Sheet sheet = workbook.getSheetAt(i);
                // 判断 是否为空
                if (sheet == null) {
                    continue;
                }
                // 获取第一行的标题
                Row rowTitle = sheet.getRow(0);
                // 获取最后的行数
                Integer rowCount = sheet.getLastRowNum();
                // 遍历数据行 [从第二行开始，第一行是标题]
                for (int j = 1; j < rowCount + 1; j++) {
                    // 获取行数
                    lineNumber = j;
                    // 获取数据行
                    Row row = sheet.getRow(j);
                    // 判断行是否为空
                    if (isRowEmpty(row)) {
                        continue;
                    }
                    // 获取行最后的单元格
                    short cellCount = row.getLastCellNum();
                    // 通过反射，填充数据
                    T obj = classes.newInstance();
                    
                 // 判断是否存在行号参数
                	if(existRow) {
                		Method rowMethod = classes.getDeclaredMethod("setRow", Integer.class);
                		rowMethod.invoke(obj, j + 1);
                	}
                	
                    // 遍历单元格
                    for (short k = 0; k < properties.length; k++) {
                        // 获取标题
                        errorTitle = rowTitle.getCell(k).getStringCellValue();
                        // 获取单元格 第几列
                        cellNumber = k;
                        // 获取单元格
                        Cell cell = row.getCell(k);
                        // 判断单元格
                        if (cell == null) {
                            continue;
                        }
                        // 根据属性名，获取字段
                        Method method = null;
                        // 获取属性类型
                        Field field = classes.getDeclaredField(properties[k]);
                        /// 判断属性类型 [ 浮点类型]
                        if (field.getType().getName().equals("java.lang.Double")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            // 判断是否存在 %
                            String valueStr = cell.getRichStringCellValue().getString();
                            if (valueStr.indexOf("%") != -1) {
                                Double value = 0d;
                                valueStr = valueStr.replace("%", "");
                                // 将数据转成值
                                value = Double.valueOf(valueStr) / 100;
                                // 设值 [ 类型 ]
                                method.invoke(obj, value);
                            } else {
                                method.invoke(obj, Double.valueOf(cell.getRichStringCellValue().getString()));
                            }
                        }
                        /// 判断属性类型 [ Short ]
                        if (field.getType().getName().equals("java.lang.Short")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj, Short.valueOf(cell.getRichStringCellValue().getString()));
                        }

                        /// 判断属性类型 [ Long ]
                        if (field.getType().getName().equals("java.lang.Long")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj, Long.valueOf(cell.getRichStringCellValue().getString()));
                        }

                        /// 判断属性类型 [ Float ]
                        if (field.getType().getName().equals("java.lang.Float")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj, Float.valueOf(cell.getRichStringCellValue().getString()));
                        }

                        /// 判断属性类型 [ Byte ]
                        if (field.getType().getName().equals("java.lang.Byte")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj, Byte.valueOf(cell.getRichStringCellValue().getString()));
                        }

                        /// 判断属性类型 [ 大浮点型]
                        if (field.getType().getName().equals("java.math.BigDecimal")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj,
                                    BigDecimal.valueOf(Double.valueOf(cell.getRichStringCellValue().getString())));
                        }
                        // 整型类型
                        if (field.getType().getName().equals("java.lang.Integer")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj, Integer.valueOf(cell.getRichStringCellValue().getString()));
                        }
                        // 时间类型
                        if (field.getType().getName().equals("java.util.Date")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            try {
                                method.invoke(obj, cell.getDateCellValue());
                            } catch (Exception e) {
                                method.invoke(obj, DateUtils.parse(cell.getRichStringCellValue().getString(),
                                        "yyyy-MM-dd HH:mm:ss"));
                            }
                        }
                        // 字符串类型
                        if (field.getType().getName().equals("java.lang.String")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj, cell.getRichStringCellValue().getString());
                        }
                    }
                    // 将对象存入集合
                    list.add(obj);
                }
            }
            // 返回数据集合
            return list;
        } catch (Exception e) {
            e.printStackTrace();
            throw new IOException("Excel文件中，sheet" + sheetNumber + "的第" + (lineNumber + 1) + "行第" + (cellNumber + 1)
                    + "，[ " + errorTitle + " ]列导入错误，请检查！");
        }
    }

    /**
     * Excel 导入并返回行
     *
     * @param <T>
     * @param input
     * @param classes
     * @param properties
     * @param
     * @return
     * @throws IOException
     */
    public static <T> List<T> importExcel(InputStream input, Class<T> classes, String[] properties, String[] title)
            throws IOException {
        // 判断输入流是否为空
        if (input == null) {
            return null;
        }
        // 创建变量，记录错误的行号
        long lineNumber = 0;
        Integer sheetNumber = 0;
        short cellNumber = 0;
        // 创建变量，接收标题名称
        String errorTitle = "";

        String errorMessage = "Excel文件中，sheet" + sheetNumber + "的第" + (lineNumber + 1) + "行第" + (cellNumber + 1) + "，[ "
                + errorTitle + " ]列导入错误，请检查！";

        try {
            // 创建数据集合
            List<T> list = new ArrayList<>();
            // 创建 workbook
            Workbook workbook = null;
            // 判断
            if (!input.markSupported()) {
                input = new PushbackInputStream(input, 8);
            }
            // 2003版 xls
            if (POIFSFileSystem.hasPOIFSHeader(input)) {
                workbook = new HSSFWorkbook(input);
            }
            // 2007版 xlsx
            if (POIXMLDocument.hasOOXMLHeader(input)) {
                // OPCPackage.open(is)取得一个文件的读写权限
                workbook = new XSSFWorkbook(OPCPackage.open(input));
            }
            // 获取sheet页
            Integer sheetCount = workbook.getNumberOfSheets();
            // 遍历sheet页
            for (int i = 0; i < sheetCount; i++) {

                // 获取 sheet 号
                sheetNumber = i;
                // 获取sheet
                Sheet sheet = workbook.getSheetAt(i);
                // 判断 是否为空
                if (sheet == null) {
                    continue;
                }
                // 获取第一行的标题
                Row rowTitle = sheet.getRow(0);
                if (rowTitle != null) {
                    if (rowTitle.getLastCellNum() != title.length) {
                        errorMessage = "Excel文件中，sheet" + sheetNumber + "的列数量不符合要求，请检查！";
                        throw null;
                    }
                    for (int j = 0; j < title.length; j++) {
                        if (!title[j].equals(rowTitle.getCell(j).getStringCellValue())) {
                            errorMessage = "Excel文件中，第[" + (j + 1) + "]列[" + rowTitle.getCell(j).getStringCellValue()
                                    + "]名称与标准列名[" + title[j] + "]不一致！";
                            throw null;
                        }
                    }
                }

                // 获取最后的行数
                Integer rowCount = sheet.getLastRowNum();
                // 遍历数据行 [从第二行开始，第一行是标题]
                for (int j = 1; j < rowCount + 1; j++) {
                    // 获取行数
                    lineNumber = j;
                    // 获取数据行
                    Row row = sheet.getRow(j);
                    // 判断行是否为空
                    if (isRowEmpty(row)) {
                        continue;
                    }
                    // 获取行最后的单元格
                    short cellCount = row.getLastCellNum();
                    // 通过反射，填充数据
                    T obj = classes.newInstance();
                    // 遍历单元格
                    for (short k = 0; k < properties.length; k++) {
                        // 获取标题
                        errorTitle = rowTitle.getCell(k).getStringCellValue();
                        // 获取单元格 第几列
                        cellNumber = k;
                        // 获取单元格
                        Cell cell = row.getCell(k);
                        // 判断单元格
                        if (cell == null) {
                            continue;
                        }
                        // 根据属性名，获取字段
                        Method method = null;
                        // 获取属性类型
                        Field field = classes.getDeclaredField(properties[k]);
                        /// 判断属性类型 [ 浮点类型]
                        if (field.getType().getName().equals("java.lang.Double")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            // 判断是否存在 %
                            String valueStr = cell.getRichStringCellValue().getString();
                            if (valueStr.indexOf("%") != -1) {
                                Double value = 0d;
                                valueStr = valueStr.replace("%", "");
                                // 将数据转成值
                                value = Double.valueOf(valueStr) / 100;
                                // 设值 [ 类型 ]
                                method.invoke(obj, value);
                            } else {
                                method.invoke(obj, Double.valueOf(cell.getRichStringCellValue().getString()));
                            }
                        }
                        /// 判断属性类型 [ Short ]
                        if (field.getType().getName().equals("java.lang.Short")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj, Short.valueOf(cell.getRichStringCellValue().getString()));
                        }

                        /// 判断属性类型 [ Long ]
                        if (field.getType().getName().equals("java.lang.Long")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj, Long.valueOf(cell.getRichStringCellValue().getString()));
                        }

                        /// 判断属性类型 [ Float ]
                        if (field.getType().getName().equals("java.lang.Float")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj, Float.valueOf(cell.getRichStringCellValue().getString()));
                        }

                        /// 判断属性类型 [ Byte ]
                        if (field.getType().getName().equals("java.lang.Byte")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj, Byte.valueOf(cell.getRichStringCellValue().getString()));
                        }

                        /// 判断属性类型 [ 大浮点型]
                        if (field.getType().getName().equals("java.math.BigDecimal")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj,
                                    BigDecimal.valueOf(Double.valueOf(cell.getRichStringCellValue().getString())));
                        }
                        // 整型类型
                        if (field.getType().getName().equals("java.lang.Integer")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj, Integer.valueOf(cell.getRichStringCellValue().getString()));
                        }
                        // 时间类型
                        if (field.getType().getName().equals("java.util.Date")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            try {
                                method.invoke(obj, cell.getDateCellValue());
                            } catch (Exception e) {
                                method.invoke(obj, DateUtils.parse(cell.getRichStringCellValue().getString(),
                                        "yyyy-MM-dd HH:mm:ss"));
                            }
                        }
                        // 字符串类型
                        if (field.getType().getName().equals("java.lang.String")) {
                            // 判断
                            if (cellValueIsNull(cell)) {
                                continue;
                            }
                            method = classes.getDeclaredMethod(
                                    "set" + properties[k].substring(0, 1).toUpperCase() + properties[k].substring(1),
                                    field.getType());
                            method.invoke(obj, cell.getRichStringCellValue().getString());
                        }
                    }
                    // 将对象存入集合
                    list.add(obj);
                }
            }
            // 返回数据集合
            return list;
        } catch (Exception e) {
            e.printStackTrace();
            throw new IOException(errorMessage);
        }
    }

    /**
     * 处理日期格式
     *
     * @param cell ：单元格对象
     * @return
     */
    private static String disposeDate(Cell cell) throws Exception {
        // 处理时间格式
        if ("h:mm".equals(cell.getCellStyle().getDataFormatString())) {
            return new SimpleDateFormat("HH:mm").format(cell.getDateCellValue());
        }
        throw new Exception("时间格式错误！");
    }

    /**
     * 判断是否未空行
     *
     * @param row
     * @return
     */
    public static boolean isRowEmpty(Row row) {
        for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) {
            Cell cell = row.getCell(c);
            if (cell != null && cell.getCellType() != Cell.CELL_TYPE_BLANK)
                return false;
        }
        return true;
    }

    /**
     * 校验单元格数据是否为空
     *
     * @param cell ：单元格对象
     * @return
     */
    private static boolean cellValueIsNull(Cell cell) {
        // 判断单元格格式
        if (cell.getCellType() != 1) {
            // 所有的格式都设置为 String 类型
            cell.setCellType(Cell.CELL_TYPE_STRING);
        }
        // 判断是否为空
        if (StringUtils.isNotBlank(cell.getStringCellValue())) {
            return false;
        }
        return true;
    }
    
    public static void downLoadExcel(String fileName, Workbook workbook,
			HttpServletRequest request, HttpServletResponse response) throws IOException {
		OutputStream out = response.getOutputStream();
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		try {
			String userAgent = request.getHeader("USER-AGENT");
            if (userAgent.contains("Mozilla")) {
                fileName = new String(fileName.getBytes(), "ISO8859-1");
            } else {
                fileName = URLEncoder.encode(fileName, "utf8");
            }
			
			response.setCharacterEncoding("UTF-8");
			response.setHeader("content-Type", "application/vnd.ms-excel");
			response.setHeader("Content-Disposition", "attachment;fileName=" + fileName + ".xlsx");
			workbook.write(baos);
			response.setHeader("Content-Length", String.valueOf(baos.size()));
			out.write(baos.toByteArray());
		} catch (IOException e) {
			e.printStackTrace();
			throw e;
		} finally {
			workbook.close();
			baos.flush();
			baos.close();
			if(out != null) {
				out.flush();
				out.close();
			}
		}
	}

}
